package gbench.appdemo.mall.appitf.platform;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.WebContext;
import org.thymeleaf.templateresolver.StringTemplateResolver;

import gbench.appdemo.mall.erp.MyPlatform;
import gbench.appdemo.mall.erp.components.IEnterprise;
import gbench.appdemo.mall.erp.components.IPriceQuote;
import gbench.common.fs.FileSystem;import gbench.common.matlib.MatlibCanvas.XVec;
import gbench.common.matlib.rdd.BasePair;
import gbench.common.matlib.rdd.PVec;
import gbench.common.tree.LittleTree.IRecord;
import gbench.common.tree.LittleTree.Term;

import static gbench.common.matlib.MatlibCanvas.println;
import static gbench.common.tree.LittleTree.IRecord.*;

/**
 * http://localhost:8082/mall/platform/erp/01/offers
 * 
 * @author gbench
 *
 */
@RequestMapping("platform")
@RestController
public class PlatformController {

    /**
     * 获取 企业 报价明细 需要：JunitErp.foo 生成产品目录
     * 
     * 访问路径示意: http://localhost:8082/mall/platform/myerp/01/offers <br>
     * name: myerp <br>
     * infositeid:01 , 标注 产品资料的路径代号，任意一个数字<br>
     * 
     * @param platform_name 平台名称
     * @param infositeid 信息站点id,用于 指定/定义 信息站点资源位置地址 即 infositeHome
     * @return
     */
    @RequestMapping("/{platform_name}/{infositeid}/offers")
    public IRecord offers(final @PathVariable("platform_name") String platform_name, final  @PathVariable("infositeid") Integer infositeid, final Integer cnt, final Boolean asc) {
        final var platform = platformGetter.apply(platform_name);
        final var sql = "select * from t_fortune limit 10"; // 企业范围的 sql
        final var result = computeEnterpriseOffers(platform_name, infositeid, asc, platform, sql);
        return REC("code", 0, "result", result);
    }
    
    /**
     * http://localhost:8082/mall/platform/myerp/01/offer/25100 报价单文件
     * 
     * @param platform_name 平台名
     * @param infositeid 资料信息点的id
     * @param price_quote_id  产品报价单id
     * @param width         产品报价单上的图片的宽度
     * @return
     */
    @RequestMapping("/{platform_name}/{infositeid}/offer/{id}")
    public ModelAndView offer(final @PathVariable("platform_name") String platform_name,
            final @PathVariable("infositeid") Integer infositeid, @PathVariable("id") Integer price_quote_id,
            final Integer width) {
        final var rec = this.getResources(platform_name, 0, price_quote_id);
        final var priceQuote = rec.get("priceQuote", IPriceQuote.class);
        final var files = rec.lla("files", String.class);

        ModelAndView mv = new ModelAndView();
        mv.addObject("demostration", rec.str("demostration"));// 产品展示图
        mv.addObject("files", files);
        mv.addObject("priceQuote", priceQuote);
        mv.addObject("priceQuoteHome", rec.str("priceQuoteHome"));
        mv.addObject("previewfiles", rec.get("previewfiles"));
        mv.addObject("width", width == null ? 350 : width);// 默认宽度为350;

        mv.setViewName("mall/offer");
        return mv;
    }

    /**
     * 自定义产品模板
     * 
     * http://localhost:8082/mall/platform/erp/01/offer2/25100 报价单文件
     * 
     * @return
     */
    @RequestMapping("/{platform_name}/{infositeid}/offer2/{id}")
    public void offer2(final @PathVariable("platform_name") String platform_name, final @PathVariable("infositeid") Integer infositeid,
            @PathVariable("id") Integer id, HttpServletRequest request, HttpServletResponse response) {

        final var rec = this.getResources(platform_name, 0, id);
        final var datafiles = rec.get("datafiles",(PVec<String,String>)null); // 提取数据文件
        final var defaulttemplate = "templates/mall/offer.html";
        final WebContext ctx = new WebContext(request, response, servletContext, request.getLocale());
        
        ctx.setVariable("demostration", rec.str("demostration"));// 产品图片
        ctx.setVariable("files", rec.lla("files", String.class));
        ctx.setVariable("priceQuote", rec.get("priceQuote", IPriceQuote.class));
        ctx.setVariable("priceQuoteHome", rec.str("priceQuoteHome"));
        ctx.setVariable("previewfiles", rec.get("previewfiles"));
        
        var templatefile = defaulttemplate;
        var flag = false;// 是否使用自定义模版
        if (datafiles != null) {
            final var t0 = datafiles.groupByKey().pget("html"); // 按照扩展名进行分组
            final var t1 = datafiles.groupByKey().pget("html"); // 按照扩展名进行分组
            final var opt = Stream.of(t0, t1).filter(Objects::nonNull).flatMap(e -> e.stream()).findAny();
            templatefile = opt.orElse(templatefile);
            if (opt.isPresent()) flag = true;
        } // datafiles
        
        println("模版文件为:",templatefile);
        try (final InputStream inputStream = flag
                ? new FileInputStream(templatefile)
                : ClassLoader.getSystemResourceAsStream(defaulttemplate);) {
            
            final var lines = new BufferedReader(new InputStreamReader(inputStream)).lines()
                    .collect(Collectors.joining(System.lineSeparator()));
            //println(lines);
            response.setContentType("text/html; charset=utf-8"); // 设置文件输出MIME
            this.getTemplateEngine().process(lines, ctx, response.getWriter()); // 模版输出
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
     
    
    /**
     * 获取 企业 报价明细 需要：JunitErp.foo 生成产品目录
     * 
     * 访问路径示意: http://localhost:8082/mall/platform/myerp/01/1/offers <br>
     * name: myerp <br>
     * infositeid:01 , 标注 产品资料的路径代号，任意一个数字<br>
     * 
     * @param platform_name 平台名称
     * @param infositeid 信息站点id,用于 指定/定义 信息站点资源位置地址 即 infositeHome
     * @return
     */
    @RequestMapping("/{platform_name}/{infositeid}/{enterpriseid}/offers")
    public IRecord offersOf(final @PathVariable("platform_name") String platform_name, final  @PathVariable("infositeid") Integer infositeid, 
            @PathVariable("enterpriseid")Integer enterpriseid,final Integer cnt, final Boolean asc) {
        final var platform = platformGetter.apply(platform_name);
        final var sql = Term.FT("select * from t_fortune where id = $0",enterpriseid);
        final var result = computeEnterpriseOffers(platform_name, infositeid, asc, platform, sql);
        return REC("code", 0, "result", result);
    }

    /**
     * 计算指定企业的报价单
     * 
     * @param platform_name 平台名
     * @param infositeid 平台资料库编号
     * @param asc 价格升序标记
     * @param platform 平台对象
     * @param enterprise_sql 企业查询语句
     * @return 报价单的列表
     */
    private List<IRecord> computeEnterpriseOffers(final String platform_name, final Integer infositeid, final Boolean asc,
            final MyPlatform platform, final String enterprise_sql) {
        
        final var result = platform.withTransaction(erpApp -> {
            final var infoSiteConfig = platform.getInfoSiteConfig(infositeid); // 信息点配置
            final var media_server_url = infoSiteConfig.str("media_server_url"); // 媒体服务器
            final var infoSite = platform.infoSiteOf(infoSiteConfig.str("home")); // 信息点
            final var enterprises = erpApp.sqlqueryS(enterprise_sql).map(e -> (IEnterprise) erpApp.new Enterprise(e).initialize()).collect(XVec.xveclc());
            final var pcts = enterprises.flatMap(e -> Optional.ofNullable(e.getCatalog())
                    .map(catalog -> catalog.stream(q -> BasePair.bp(q.getProduct().getName(), BasePair.bp(q, e))))
                    .orElse(Stream.empty())).collect(PVec.pvec2clc());

            // 生成产品列表
            return pcts.groupByX(e -> e._1(), XVec::OF).fmap(e -> {
                final var pct = e._1(); // 产品名称
                final var quotes = e._2().fmap(p -> {
                    final var enterprise = p._2()._2();
                    final var priceQuote = p._2()._1();
                    final var price = priceQuote.getUnitPrice().getAmount();
                    final var quotesite = Term.FT("$0$1/$2",media_server_url,infoSite.getPriceQuoteHome(priceQuote),"readme.txt");
                    final var offerurl = Term.FT("$0/$1/$2/offer/$3","/mall/platform",platform_name,infositeid,priceQuote.getId());
                    final var rs = this.getResources(platform_name, infositeid, priceQuote.getId());
                    final var rec = REC(
                            "name", enterprise.getName(), 
                            "price", price,
                            "quotesite", quotesite, 
                            "offerurl", offerurl, 
                            "resources", rs.filter("demostration,imagefiles,files,previewfiles"), 
                            "attrs", priceQuote.attrs());
                    return rec;
                }).sorted(IRecord.cmp("price", asc == null ? true : false)); // 报价列表
                
                final var rec = REC("pct", pct, "offers", quotes.list());
                
                // println(rec);
                
                return rec;
            }); // computeOffers
            
        }).list();
        return result;
    }
    
    /**
     * 从 特定平台的信息点上 获取资源信息
     * 
     * @param platform_name  平台名
     * @param infositeid 信息点编号
     * @param price_quote_id 报价单编号
     * @return IRecord 结果集合记录
     */
    public IRecord getResources(final String platform_name, final Integer infositeid, final Integer price_quote_id) {
        final var platform = platformGetter.apply(platform_name);
        final var infoSite = platform.infoSiteOf(infositeid);// 信息站
        final var priceQuote = platform.withTransaction(erpApp -> erpApp.priceQuoteOf(price_quote_id));
        final var demostration_file = new AtomicReference<String>(); // 展示图
        final var datafiles = infoSite.getResources(priceQuote).lla("files", String.class).stream()
                .map(e->BasePair.bp(FileSystem.extensionpicker(e).toLowerCase(), e.replace("\\", "/")))
                .collect(PVec.pvec2clc());
        final var priceQuoteHome = infoSite.getPriceQuoteHome(price_quote_id);
        final var imagefiles = new LinkedList<String>();
        
        final var files = datafiles.map(e -> {
            final var extension = e._1(); // 提取文件扩展名
            final var path = e._2(); // 文件名称
            final var name = FileSystem.namepicker(path);
            final var rb = IRecord.rb("path,extension"); // 文件项结构
            switch (extension) { // 文件类型判断
                case "jpg": case "jpeg": case "webp": case "pcx": case "gif": case "bmp": case "tif": case "tga": case "exif": case "fpx":
                case "svg": case "psd": case "cdr":  case "pcd": case "dxf": case "ufo":  case "eps":  case "ai":  case "png": case "hdri":
                case "raw":  case "wmf": case "flic": case "emf": case "ico": case "jfif": { // 图片类型
                    imagefiles.add(path);
                    if (demostration_file.get() == null) {
                        if (name.startsWith("index")) {
                            demostration_file.set(path);
                            return null;
                        }
                    } else {
                        return rb.get(path, extension).toMap();
                    } // if
                } // case 图片
                
                default: { // 默认类型
                    return rb.get(path,extension).toMap();
                } // default 
        }}).filter(e -> e != null).collect(Collectors.toList()); // [(path,extension)] 的 MAP集合 
        
        // 演示文件设置
        if(demostration_file.get()==null) {
            if (imagefiles.size() <1 ) {
                demostration_file.set("D:/sliced/files/products/valuables/gold.jpg");
            } else {
                demostration_file.set(imagefiles.get(0));
            }// if
        }// if
        
        final var pvec = XVec.OF(imagefiles).collect(PVec.pvec1clc(e->FileSystem.namepicker(e).startsWith("preview")));
        final var mm = pvec.groupBy(e->e._1());
        final var previewfiles = Optional.ofNullable(mm.get(true)).map(ll->ll.stream().map(e->e._2()).collect(Collectors.toList())).orElse(null);
        final var _imagefiles = Optional.ofNullable(mm.get(false)).map(ll->ll.stream().map(e->e._2()).collect(Collectors.toList())).orElse(null);
        
        println("previewfiles",previewfiles);
        println("_imagefiles",_imagefiles);
        
        return REC("demostration", demostration_file.get(), "files", files.stream().filter(e -> {
            if (previewfiles == null)
                return true;
            return !previewfiles.contains(e.get("path"));
        }).collect(Collectors.toList()), "priceQuote", priceQuote, "priceQuoteHome", priceQuoteHome, "datafiles",
                datafiles, "imagefiles", _imagefiles, "previewfiles", previewfiles);
    }
    
    /**
     * 获取 模版引擎
     * @return 模版引擎
     */
    public TemplateEngine getTemplateEngine() {
        if(templateEngine==null) {
            final var templateResolver = new StringTemplateResolver();
            templateResolver.setCacheTTLMs(Long.valueOf(3600000L));
            templateResolver.setCacheable(false);
            this.templateEngine = new TemplateEngine();
            this.templateEngine.setTemplateResolver(templateResolver);
        } // if
        
        return this.templateEngine;
    }

    private TemplateEngine templateEngine = null;

    /**
     * BootstrapMall 的 platformGetter 给予注入
     */
    @Qualifier("platformGetter")
    @Autowired
    private Function<String, MyPlatform> platformGetter;
    
    @Autowired
    private ServletContext servletContext;
    
}
